﻿// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for full license information.

using ReactiveUI.Tests.Infrastructure.StaticState;

namespace ReactiveUI.Tests;

/// <summary>
/// Tests for POCO observable property resolution.
/// </summary>
/// <remarks>
/// This test fixture is marked as NonParallelizable because it calls RxApp.EnsureInitialized(),
/// which initializes global static state including the service locator. This state must not be
/// concurrently initialized by parallel tests.
/// </remarks>
[TestFixture]
[NonParallelizable]
public class PocoObservableForPropertyTests
{
    private RxAppSchedulersScope? _schedulersScope;

    [SetUp]
    public void SetUp()
    {
        _schedulersScope = new RxAppSchedulersScope();
    }

    [TearDown]
    public void TearDown()
    {
        _schedulersScope?.Dispose();
    }

#pragma warning disable CA1812 // Class is not instantiated

    ////private static TestLogger? _testLoggerForNotificationPocoErrorOnBind;

    [Test]
    public void CheckGetAffinityForObjectValues()
    {
        RxApp.EnsureInitialized();
        var instance = new POCOObservableForProperty();

        using (Assert.EnterMultipleScope())
        {
            Assert.That(instance.GetAffinityForObject(typeof(PocoType), null!, false), Is.EqualTo(1));
            Assert.That(instance.GetAffinityForObject(typeof(INPCClass), null!, false), Is.EqualTo(1));
        }
    }

    ////[Fact(Skip = "Test Scheduler is null on occasions")]
    ////public void NotificationPocoErrorOnBind()
    ////{
    ////    RxApp.EnsureInitialized();

    ////// Use same logger, when the test is executed multiple times in the same AndroidRunner/AppDomain/AssemblyLoadContext
    ////if (_testLoggerForNotificationPocoErrorOnBind is null)
    ////{
    ////    _testLoggerForNotificationPocoErrorOnBind = new TestLogger();
    ////}

    ////// Run test twice and verify that POCO message is logged only once.
    ////for (var i = 0; i < 2; i++)
    ////{
    ////    using (var testLoggerRegistration = new TestLoggerRegistration(_testLoggerForNotificationPocoErrorOnBind))
    ////    {
    ////        var instance = new POCOObservableForProperty();

    ////        var testLogger = testLoggerRegistration.Logger;

    ////        var testClass = new PocoType();

    ////        Expression<Func<PocoType, string>> expr = x => x.Property1!;
    ////        var exp = Reflection.Rewrite(expr.Body);

    ////        var propertyName = exp.GetMemberInfo()?.Name;

    ////        if (propertyName is null)
    ////        {
    ////            throw new InvalidOperationException("propertyName should not be null");
    ////        }

    ////        instance.GetNotificationForProperty(testClass, exp, propertyName, false).Subscribe(_ => { });

    ////        Assert.That(testLogger.LastMessages.Count > 0, Is.True);

    ////        var expectedMessage = $"{nameof(POCOObservableForProperty)}: The class {typeof(PocoType).FullName} property {nameof(PocoType.Property1)} is a POCO type and won't send change notifications, WhenAny will only return a single value!";
    ////        Assert.That(testLogger.LastMessages[0], Is.EqualTo(expectedMessage));

    ////        // Verify that the message is logged only once
    ////        foreach (var logMessage in testLogger.LastMessages.Skip(1))
    ////        {
    ////            Assert.That(logMessage, Is.Not.EqualTo(expectedMessage));
    ////        }
    ////    }
    ////}
    ////}

    ////[Fact(Skip = "Test Scheduler is null on occasions")]
    ////public void NotificationPocoSuppressErrorOnBind()
    ////{
    ////    RxApp.EnsureInitialized();
    ////using (var testLoggerRegistration = new TestLoggerRegistration())
    ////{
    ////    var instance = new POCOObservableForProperty();

    ////    var testLogger = testLoggerRegistration.Logger;

    ////    var testClass = new PocoType();

    ////    Expression<Func<PocoType, string>> expr = x => x.Property1!;
    ////    var exp = Reflection.Rewrite(expr.Body);

    ////    var propertyName = exp.GetMemberInfo()?.Name;

    ////    if (propertyName is null)
    ////    {
    ////        throw new InvalidOperationException("propertyName should not be null");
    ////    }

    ////    instance.GetNotificationForProperty(testClass, exp, propertyName, false, true).Subscribe(_ => { });

    ////    testLogger.LastMessages.Should().NotContain(m => m.Contains(nameof(POCOObservableForProperty)));
    ////}
    ////}

    private class PocoType
    {
        public string? Property1 { get; set; }

        public string? Property2 { get; set; }
    }

    private class INPCClass : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler? PropertyChanged;

        public void NotifyPropertyChanged() => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(string.Empty));
    }

    ////private class TestLogger : ILogger
    ////{
    ////    public List<string> LastMessages { get; } = new();

    ////    public LogLevel Level => LogLevel.Debug;

    ////    public void Write(Exception exception, string message, Type type, LogLevel logLevel) => LastMessages.Add(message);

    ////    public void Write(string message, LogLevel logLevel) => LastMessages.Add(message);

    ////    public void Write(Exception exception, string message, LogLevel logLevel) => LastMessages.Add(message);

    ////    public void Write([Localizable(false)] string message, [Localizable(false)] Type type, LogLevel logLevel) => LastMessages.Add(message);
    ////}

    ////private sealed class TestLoggerRegistration : IDisposable
    ////{
    ////    private readonly List<ILogger> _originalLoggers;

    ////    public TestLoggerRegistration()
    ////        : this(null)
    ////    {
    ////    }

    ////    public TestLoggerRegistration(TestLogger? testLogger)
    ////    {
    ////        _originalLoggers = Locator.Current.GetServices<ILogger>().ToList();

    ////        Logger = testLogger ?? new TestLogger();
    ////        Locator.CurrentMutable.RegisterConstant<ILogger>(Logger);
    ////    }

    ////    public TestLogger Logger { get; }

    ////    public void Dispose()
    ////    {
    ////        // It's not possible to unregister specific logger,
    ////        // so all are unregistered and originals are re-registered.
    ////        Locator.CurrentMutable.UnregisterAll<ILogger>();

    ////        foreach (var logger in _originalLoggers)
    ////        {
    ////            Locator.CurrentMutable.RegisterConstant<ILogger>(logger);
    ////        }
    ////    }
    ////}

#pragma warning restore CA1812 // Class is not instantiated
}
